package com.itheima.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itheima.domain.Category;
import com.itheima.domain.Comment;
import com.itheima.domain.Goods;
import com.itheima.mapper.CategoryMapper;
import com.itheima.mapper.CommentMapper;
import com.itheima.mapper.GoodsMapper;
import com.itheima.vo.Demo003Vo;
import com.itheima.vo.Demo004Vo;
import com.itheima.vo.Demo005Vo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 纯MyBatisPlus实现
 *
 * @author itheima
 * @since 2022-02-09
 */
@Service
public class MyBatisPlusService {

    @Autowired
    private GoodsMapper goodsMapper;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private CommentMapper commentMapper;

    /**
     * 一主一从
     * 主表一条数据，对应从表一条数据
     * <p>
     * 举例：查询一条商品信息，其中分类名来源于分类表，返回字段如下
     * goods_id   商品id，来源于商品表
     * goods_name 商品名，来源于商品表
     * cate_id    分类id，来源于商品表
     * cate_name  分类名，来源于分类表
     * price      商品金额，来源于商品表
     */
    public Demo003Vo demo003(String goodsId) {
        // 步骤一：selectOne查询商品表数据
        LambdaQueryWrapper<Goods> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Goods::getGoodsId, goodsId);
        Goods goods = goodsMapper.selectOne(wrapper);

        // 步骤二：判空，如果主表数据为空，就没有往下查的必要了
        if (Objects.isNull(goods)) {
            return null;
        }

        // 步骤三：selectOne查询分类表数据
        LambdaQueryWrapper<Category> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(Category::getCateId, goods.getCateId());
        Category category = categoryMapper.selectOne(wrapper1);

        // 步骤四：创建vo，准备组装两张表数据
        Demo003Vo vo = new Demo003Vo();

        // 步骤五：使用copyProperties方法，将goods对象数据复制到vo中
        BeanUtils.copyProperties(goods, vo);

        // 步骤六：使用copyProperties方法，将category对象数据复制到vo中
        // 记得判空，因为如果category为空，调用copyProperties会报空指针
        if (Objects.nonNull(category)) {
            BeanUtils.copyProperties(category, vo);
        }

        // 返回结果
        return vo;
    }

    /**
     * 一主多从
     * 主表一条数据，对应多条从表数据
     * <p>
     * 举例：查询一条商品信息，以及对应的评论列表，组装后返回
     * 返回字段如下：
     * goods_id     商品id，来源于商品表
     * goods_name   商品名，来源于商品表
     * price        商品金额，来源于商品表
     * commentList  评论列表，来源于评论表
     */
    public Demo004Vo demo004(String goodsId) {
        // 步骤一：selectOne查询商品表数据
        LambdaQueryWrapper<Goods> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Goods::getGoodsId, goodsId);
        Goods goods = goodsMapper.selectOne(wrapper);

        // 步骤二：判空，如果主表数据为空，就没有往下查的必要了
        if (Objects.isNull(goods)) {
            return null;
        }

        // 步骤三：selectList查询评论列表数据
        LambdaQueryWrapper<Comment> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(Comment::getGoodsId, goods.getGoodsId());
        List<Comment> commentList = commentMapper.selectList(wrapper1);

        // 步骤四：构建返回值结构
        Demo004Vo vo = new Demo004Vo();

        // 步骤五：使用copyProperties方法，将goods对象数据复制到vo中
        BeanUtils.copyProperties(goods, vo);

        // 步骤六：将评论列表数据赋值给vo
        vo.setCommentList(commentList);

        // 返回
        return vo;
    }

    /**
     * 多主多从
     * 主表多条数据，每条主表数据对应一条从表数据
     */
    public List<Demo005Vo> demo005(String cateId) {
        // 步骤一：selectList查询商品列表数据（要分页的话，这里可以改成selectPage）
        LambdaQueryWrapper<Goods> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Goods::getCateId, cateId);
        List<Goods> goodsList = goodsMapper.selectList(wrapper);
        if (CollUtil.isEmpty(goodsList)) {
            return null;
        }

        // 步骤二：使用hutool工具，提取cateId字段，形成一个cateId组成的列表
        List<String> cateIdList = CollUtil.getFieldValues(goodsList, "cateId", String.class);
        if (CollUtil.isEmpty(cateIdList)) {
            return null;
        }

        // 步骤三：上一步提取的字段列表，作为条件，查询对应的分类列表
        LambdaQueryWrapper<Category> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.in(Category::getCateId, cateIdList);
        List<Category> categoryList = categoryMapper.selectList(wrapper1);

        // 步骤四：将分类列表转为，以分类id作为key，Category类作为值的Map结构
        // 这么做是为了下一步组合数据时方便
        Map<Object, Category> categoryMap = CollUtil.fieldValueMap(categoryList, "cateId");

        // 步骤五：声明返回值voList
        List<Demo005Vo> voList = new ArrayList<>();

        // 步骤六：遍历商品列表
        for (Goods goods : goodsList) {
            // 注意判空，否则后面会出现空指针
            if (Objects.isNull(goods)) {
                continue;
            }

            // 声明vo
            Demo005Vo vo = new Demo005Vo();

            // goods对象复制给vo
            BeanUtils.copyProperties(goods, vo);

            // 根据主表goods对象中的cateId，获取对应的Category详细信息
            Category category = categoryMap.get(goods.getCateId());
            if (Objects.nonNull(category)) {
                vo.setCategoryName(category.getCateName());
            }

            voList.add(vo);
        }

        // 返回结果
        return voList;
    }
}
